package com.enjoyor.soa.traffic.frame.interceptor;

import com.alibaba.fastjson.JSON;
import com.enjoyor.soa.traffic.frame.annotation.MethodDescribe;
import com.enjoyor.soa.traffic.util.helper.LoggerHelper;
import com.enjoyor.soa.traffic.util.helper.ResultHelper;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class DubboServiceInterceptor {

    private static final Logger logger = Logger.getLogger(DubboServiceInterceptor.class);
    private String methodInfo;
    private long startTime;
    private long endTime;

    @Pointcut("(execution(* com.enjoyor.soa.traffic.server.**.dubbo..*(..)))")
    public void serviceMethodPointcut() {
    }

    @Before("serviceMethodPointcut()")
    public void doBefore(JoinPoint joinPoint) {
        this.startTime = System.currentTimeMillis();
        String methodInfo = "";
        Class<?> targetClass = joinPoint.getTarget().getClass();
        String className = targetClass.getName();
        methodInfo = methodInfo + className;

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        methodInfo = methodInfo + "." + methodName;
        Object[] parameters = joinPoint.getArgs();

        String parameterStr = "";

        if (parameters != null && parameters.length > 0) {

            for (Object object : parameters) {

                if (object != null) {

                    // Gson gson = new
                    // GsonBuilder().serializeSpecialFloatingPointValues().create();

                    // parameterStr = parameterStr +
                    // object.getClass().getSimpleName() + " : " +
                    // gson.toJson(object) + ",";

                    parameterStr = parameterStr + object.getClass().getSimpleName() + " : " + JSON.toJSONString(object)
                            + ",";
                }

            }

            if (parameterStr.endsWith(",")) {

                int indx = parameterStr.lastIndexOf(",");

                parameterStr = parameterStr.substring(0, indx)
                        + parameterStr.substring(indx + 1, parameterStr.length());

            }

        }

        this.methodInfo = methodInfo;
        logger.info(String.format("DubboService start, method: {%s}, params: {%s}",
                new Object[] { this.methodInfo, parameterStr }));
    }

    @AfterThrowing(pointcut = "serviceMethodPointcut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        logger.error(
                String.format("DubboService exception, method: {%s}, msg: {%s}", new Object[] { this.methodInfo, e }));
    }

    @AfterReturning(value = "serviceMethodPointcut()", argNames = "rtv", returning = "rtv")
    public void afterInsertMethod(JoinPoint jp, Object rtv) throws Throwable {

        //Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create();

        this.endTime = System.currentTimeMillis();
        long costMs = this.endTime - this.startTime;

        logger.info(String.format("DubboService result: %s", new Object[] { JSON.toJSONString(rtv) }));

        logger.info(String.format("DubboService end, method: {%s}, time: {%s}ms",
                new Object[] { this.methodInfo, Long.valueOf(costMs) }));

    }

    @Around(value = "serviceMethodPointcut()")
    public Object exec(ProceedingJoinPoint proceedingJoinPoint) {
        Object result = null;
        try{
            result = proceedingJoinPoint.proceed();
        }catch (Exception e){
            result = ResultHelper.getResult(e);

            Object[] parameters = proceedingJoinPoint.getArgs();
            MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
            Method method = signature.getMethod();
            String methodName = method.getName();
            String methodContent = methodName;
            //获取真实方法发射对象
            Method realMethod = proceedingJoinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), method.getParameterTypes());
            if(realMethod.isAnnotationPresent(MethodDescribe.class)){
                MethodDescribe md = (MethodDescribe) realMethod.getAnnotation(MethodDescribe.class);
                methodContent = md.content();
            }
            LoggerHelper.writeErrorLogInfo(methodContent+"方法执行异常", this.getClass().getSimpleName(),methodName,(Exception) e,parameters);

            logger.error(
                    String.format("DubboService exception, method: {%s}, msg: {%s}", new Object[] { this.methodInfo, e }));
        }finally {
            return result;
        }
    }



}
